package fr.inria.phoenix.diasuite.framework.controller.answercontroller;

import fr.inria.diagen.core.ServiceConfiguration;
import fr.inria.diagen.core.service.composite.CompositeException;
import fr.inria.diagen.core.exception.InvocationException;
import fr.inria.diagen.core.network.RemoteServiceInfo;
import fr.inria.diagen.core.service.local.Service;
import fr.inria.diagen.core.service.proxy.Proxy;

import fr.inria.phoenix.diasuite.framework.context.answer.AnswerValue;

/**
 * <pre>
controller AnswerController{
 * 	when provided Answer do Off on Cooker;
 * }
</pre>
 */
@SuppressWarnings("all")
public abstract class AbstractAnswerController extends Service {
    
    public AbstractAnswerController(ServiceConfiguration serviceConfiguration) {
        super("/Controller/AnswerController/", serviceConfiguration);
    }
    
    // Methods from the Service class
    @Override
    protected final void internalPostInitialize() {
        subscribeValue("answer", "/Context/Answer/"); // subscribe to Answer context
        postInitialize();
    }
    
    @Override
    public final void valueReceived(java.util.Map<String, Object> properties, RemoteServiceInfo source, String eventName, Object value, Object... indexes) {
        if (eventName.equals("answer") && source.isCompatible("/Context/Answer/")) {
            AnswerValue answerValue = new AnswerValue((java.lang.Boolean) value);
            
            onAnswer(answerValue, new DiscoverForAnswer());
        }
    }
    // End of methods from the Service class
    
    // Interaction contract implementation
    /**
     * This method is called when the <code>Answer</code> context publishes a value.
     * 
     * <pre>
     * when provided Answer do Off on Cooker;
     * </pre>
     * 
     * @param answer the value of the <code>Answer</code> context.
     * @param discover a discover object to get context values and action methods
     */
    protected abstract void onAnswer(AnswerValue answer, DiscoverForAnswer discover);
    
    // End of interaction contract implementation
    
    // Discover object for Answer
    /**
     * An object to discover devices and contexts for the following interaction contract:
     * 
     * <code>
     * when provided Answer do Off on Cooker;
     * </code>
     */
    protected final class DiscoverForAnswer {
        private final CookerDiscovererForAnswer cookerDiscoverer = new CookerDiscovererForAnswer(AbstractAnswerController.this);
        
        /**
         * @return a {@link CookerDiscovererForAnswer} object to discover <code>Cooker</code> devices
         */
        public CookerDiscovererForAnswer cookers() {
            return cookerDiscoverer;
        }
    }
    
    /**
     * Discover object that will exposes the <code>Cooker</code> devices to execute action on for the
     * <code>when provided Answer</code> interaction contract.
    
    <pre>
    device Cooker extends Appliance {
    }
    </pre>
     */
    protected final static class CookerDiscovererForAnswer {
        private Service serviceParent;
        
        private CookerDiscovererForAnswer(Service serviceParent) {
            super();
            this.serviceParent = serviceParent;
        }
        
        private CookerCompositeForAnswer instantiateComposite() {
            return new CookerCompositeForAnswer(serviceParent);
        }
        
        /**
         * Returns a composite of all accessible <code>Cooker</code> devices
         * 
         * @return a {@link CookerCompositeForAnswer} object composed of all discoverable <code>Cooker</code>
         */
        public CookerCompositeForAnswer all() {
            return instantiateComposite();
        }
        
        /**
         * Returns a proxy to one out of all accessible <code>Cooker</code> devices
         * 
         * @return a {@link CookerProxyForAnswer} object pointing to a random discoverable <code>Cooker</code> device
         */
        public CookerProxyForAnswer anyOne() {
            return all().anyOne();
        }
        
        /**
         * Returns a composite of all accessible <code>Cooker</code> devices whose attribute <code>id</code> matches a given value.
         * 
         * @param id The <code>id<code> attribute value to match.
         * @return a {@link CookerCompositeForAnswer} object composed of all matching <code>Cooker</code> devices
         */
        public CookerCompositeForAnswer whereId(java.lang.String id) throws CompositeException {
            return instantiateComposite().andId(id);
        }
        
        /**
         * Returns a composite of all accessible <code>Cooker</code> devices whose attribute <code>location</code> matches a given value.
         * 
         * @param location The <code>location<code> attribute value to match.
         * @return a {@link CookerCompositeForAnswer} object composed of all matching <code>Cooker</code> devices
         */
        public CookerCompositeForAnswer whereLocation(java.lang.String location) throws CompositeException {
            return instantiateComposite().andLocation(location);
        }
        
        /**
         * Returns a composite of all accessible <code>Cooker</code> devices whose attribute <code>user</code> matches a given value.
         * 
         * @param user The <code>user<code> attribute value to match.
         * @return a {@link CookerCompositeForAnswer} object composed of all matching <code>Cooker</code> devices
         */
        public CookerCompositeForAnswer whereUser(java.lang.String user) throws CompositeException {
            return instantiateComposite().andUser(user);
        }
    }
    
    /**
     * A composite of several <code>Cooker</code> devices to execute action on for the
     * <code>when provided Answer</code> interaction contract.
    
    <pre>
    device Cooker extends Appliance {
    }
    </pre>
     */
    protected final static class CookerCompositeForAnswer extends fr.inria.diagen.core.service.composite.Composite<CookerProxyForAnswer> {
        private CookerCompositeForAnswer(Service serviceParent) {
            super(serviceParent, "/Device/Device/PhysicalDevice/Appliance/Cooker/");
        }
        
        @Override
        protected CookerProxyForAnswer instantiateProxy(RemoteServiceInfo rsi) {
            return new CookerProxyForAnswer(service, rsi);
        }
        
        /**
         * Returns this composite in which a filter was set to the attribute <code>id</code>.
         * 
         * @param id The <code>id<code> attribute value to match.
         * @return this {@link CookerCompositeForAnswer}, filtered using the attribute <code>id</code>.
         */
        public CookerCompositeForAnswer andId(java.lang.String id) throws CompositeException {
            filterByAttribute("id", id);
            return this;
        }
        
        /**
         * Returns this composite in which a filter was set to the attribute <code>location</code>.
         * 
         * @param location The <code>location<code> attribute value to match.
         * @return this {@link CookerCompositeForAnswer}, filtered using the attribute <code>location</code>.
         */
        public CookerCompositeForAnswer andLocation(java.lang.String location) throws CompositeException {
            filterByAttribute("location", location);
            return this;
        }
        
        /**
         * Returns this composite in which a filter was set to the attribute <code>user</code>.
         * 
         * @param user The <code>user<code> attribute value to match.
         * @return this {@link CookerCompositeForAnswer}, filtered using the attribute <code>user</code>.
         */
        public CookerCompositeForAnswer andUser(java.lang.String user) throws CompositeException {
            filterByAttribute("user", user);
            return this;
        }
        
        /**
         * Executes the <code>off()</code> action's method on all devices of this composite.
         */
        public void off() throws InvocationException {
            launchDiscovering();
            for (CookerProxyForAnswer proxy : proxies) {
                proxy.off();
            }
        }
    }
    
    /**
     * A proxy to one <code>Cooker</code> device to execute action on for the
     * <code>when provided Answer</code> interaction contract.
    
    <pre>
    device Cooker extends Appliance {
    }
    </pre>
     */
    protected final static class CookerProxyForAnswer extends Proxy {
        private CookerProxyForAnswer(Service service, RemoteServiceInfo remoteServiceInfo) {
            super(service, remoteServiceInfo);
        }
        
        /**
         * Executes the <code>off()</code> action's method on this device.
         */
        public void off() throws InvocationException {
            callOrder("off");
        }
        
        /**
         * @return the value of the <code>id</code> attribute
         */
        public java.lang.String id() {
            return (java.lang.String) callGetValue("id");
        }
        
        /**
         * @return the value of the <code>location</code> attribute
         */
        public java.lang.String location() {
            return (java.lang.String) callGetValue("location");
        }
        
        /**
         * @return the value of the <code>user</code> attribute
         */
        public java.lang.String user() {
            return (java.lang.String) callGetValue("user");
        }
    }
    // End of discover object for Answer
}
